"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.useDate = void 0;
const base_1 = require("./base");
function SET_FORMAT(date) { }
function DATE_TO_PARSE(date) {
    date.setMilliseconds(0);
    const $Y = date.getFullYear();
    const $M = date.getMonth();
    const $D = date.getDate();
    const $H = date.getHours();
    const $m = date.getMinutes();
    const $s = date.getSeconds();
    const $W = date.getDay();
    const timestamp = date.getTime();
    const item = { $Y, $M, $D, $H, $m, $s, $W, timestamp, date };
    SET_FORMAT(item);
    return item;
}
function PARAMS_HANDLER(arg1, arg2) {
    const { time, format } = (0, base_1.isObject)(arg1) ? arg1 : { time: arg1, format: arg2 };
    return {
        time: time || new Date(),
        format: format || "YYYY-MM-DD HH:mm:ss"
    };
}
/* 2. 解析 format */
// 从 format 中解析各个格式
const PATCH_ZERO = function (data, patch = false) {
    if (patch)
        return data < 10 ? `0${data}` : `${data}`;
    else
        return `${data}`;
};
const FORMATS_UTILS = {
    $Y: {
        formats: [
            { fmt: "YYYY", reg: `[0-9]{4}`, patch: date => PATCH_ZERO(date) } // 0000-9999
        ],
        write: (date, v) => {
            date.setFullYear(v);
        }
    },
    $M: {
        formats: [
            { fmt: "MM", reg: `0[1-9]|1[0-2]`, patch: data => PATCH_ZERO(data + 1, true) },
            { fmt: "M", reg: `[1-9]|1[0-2]`, patch: data => PATCH_ZERO(data + 1) } // 1-12
        ],
        write: (date, v) => {
            date.setMonth(v - 1);
        }
    },
    $D: {
        formats: [
            { fmt: "DD", reg: `0[1-9]|[1-2][0-9]|3[0-1]`, patch: data => PATCH_ZERO(data, true) },
            { fmt: "D", reg: `[1-9]|[1-2][0-9]|3[0-1]`, patch: data => PATCH_ZERO(data) } // 1-31
        ],
        write: (date, v) => {
            date.setDate(v);
        }
    },
    $H: {
        formats: [
            { fmt: "HH", reg: `0[0-9]|1[0-9]|2[0-3]`, patch: data => PATCH_ZERO(data, true) },
            { fmt: "H", reg: `[0-9]|1[0-9]|2[0-3]`, patch: data => PATCH_ZERO(data) } // 0-23
        ],
        write: (date, v) => {
            date.setHours(v);
        }
    },
    $m: {
        formats: [
            { fmt: "mm", reg: `0[0-9]|[1-5][0-9]`, patch: data => PATCH_ZERO(data, true) },
            { fmt: "m", reg: `[0-9]|[1-5][0-9]`, patch: data => PATCH_ZERO(data) } // 0-59
        ],
        write: (date, v) => {
            date.setMinutes(v);
        }
    },
    $s: {
        formats: [
            { fmt: "ss", reg: `0[0-9]|[1-5][0-9]`, patch: data => PATCH_ZERO(data, true) },
            { fmt: "s", reg: `[0-9]|[1-5][0-9]`, patch: data => PATCH_ZERO(data) } // 0-59
        ],
        write: (date, v) => {
            date.setSeconds(v);
        }
    },
    $W: {
        formats: [
            { fmt: "WW", reg: `0[0-9]|[1-4][0-9]|5[0-2]`, patch: data => PATCH_ZERO(data, true) },
            { fmt: "W", reg: `[0-9]|[1-4][0-9]|5[0-2]`, patch: data => PATCH_ZERO(data) } // 0-52
        ]
    }
};
function PARSE_FORMAT(format) {
    let hadWeek = false; // 存在周
    let hadYear = false; // 存在年
    let hadOtherFmt = false; // 非年 / 周格式
    const handler = [];
    // 将所有 [] 去除掉
    const handlerFormat = format.replace(/\[[\w^\[\]]+\]/g, "");
    Object.keys(FORMATS_UTILS).forEach(key => {
        const { formats, write } = FORMATS_UTILS[key];
        const UTILS = formats.find(item => {
            return handlerFormat.includes(item.fmt);
        });
        if (UTILS) {
            handler.push(Object.assign({ key, write }, UTILS));
            hadWeek = hadWeek ? hadWeek : key === "$W";
            hadYear = hadYear ? hadYear : key === "$Y";
            hadOtherFmt = hadOtherFmt ? hadOtherFmt : !["$Y", "$W"].includes(key);
        }
        else {
            handler.push({ key });
        }
    });
    return {
        handler,
        isWeek: hadWeek && hadYear,
        isError: hadOtherFmt ? hadWeek : false // 有其他非周年格式时不能有周格式
    };
}
function TIME_TYPE(time) {
    if ((0, base_1.isDate)(time))
        return "date"; // 传入的是时间对象
    if ((0, base_1.isString)(time))
        return "string"; // 传入的是时间文本
    if ((0, base_1.isNumber)(time))
        return "timestamp"; // 传入的是时间戳
    return false; // 传入的是无法解析的对象
}
/* 4. 根据解析后的 RegExp 从字符串类型中获取时间 */
const weeks = [7, 1, 2, 3, 4, 5, 6];
function GET_FIRST_WEEK(year, week) {
    const date = new Date(year, 0, 1, 0, 0, 0);
    const i = date.getDay();
    const diff = 24 * 60 * 60 * 1000 * (7 - weeks[i] + 1);
    const start = date.getTime() + diff;
    const end = start + 24 * 60 * 60 * 1000 * 7 - 1;
    const weekDiff = (week - 1) * 24 * 60 * 60 * 1000 * 7;
    return [new Date(start + weekDiff), new Date(end + weekDiff)];
}
function PARSE_BY_REGEXP(time, format, handler, target) {
    let execFmt = format;
    // 处理 execFmt
    let isFinish = false;
    let execFmtArr = [execFmt]; // 拆分后的结果
    let joinStr = []; // 用于拼接的字符数组
    while (!isFinish) {
        // 判断是否存在 [xxx]
        const sourceStr = execFmtArr.pop();
        const splitReg = new RegExp(/\[([\w^\[\]]+)\]/g);
        const res = splitReg.exec(sourceStr);
        if (res) {
            const [split, str] = res;
            joinStr.push(str);
            const target = sourceStr.split(split);
            const shift = target.shift();
            execFmtArr = [...execFmtArr, shift, target.join(split)];
        }
        else {
            isFinish = true;
            execFmtArr.push(sourceStr || "");
        }
    }
    handler.forEach(item => {
        const { key, fmt, reg } = item;
        const isTarget = key === target;
        if (fmt) {
            // 找到第一个 fmt，替换为匹配正则
            execFmtArr.some((item, i) => {
                const isIncludes = item.includes(fmt);
                if (isIncludes) {
                    execFmtArr[i] = execFmtArr[i].replace(fmt, isTarget ? `(${reg})` : `(?:${reg})`);
                }
                return isIncludes;
            });
            // 重新拼接，去除 []
            execFmt = execFmtArr.reduce((total, str, i) => {
                return total + str + (joinStr[i] || "");
            }, "");
        }
    });
    const result = new RegExp(`^${execFmt}$`).exec(time);
    if (result) {
        const [, res] = result;
        return res;
    }
    return false;
}
function READ_FROM_STR(time, format, handler, isWeek = false) {
    if (isWeek) {
        const year = PARSE_BY_REGEXP(time, format, handler, "$Y");
        const week = PARSE_BY_REGEXP(time, format, handler, "$W");
        if (year && week) {
            return GET_FIRST_WEEK(year, week);
        }
        else {
            return false;
        }
    }
    else {
        const date = new Date();
        date.setHours(0);
        date.setMinutes(0);
        date.setSeconds(0);
        let isError = false;
        handler.forEach(item => {
            const { key, fmt, write } = item;
            if (fmt) {
                const res = PARSE_BY_REGEXP(time, format, handler, key);
                isError = isError ? isError : !res;
                if (res)
                    write(date, res);
            }
        });
        return { isError, date };
    }
}
function useDate(arg1, arg2) {
    const { time, format } = PARAMS_HANDLER(arg1, arg2);
    const { isError, isWeek, handler } = PARSE_FORMAT(format);
    const type = TIME_TYPE(time);
    if (isError)
        return false;
    if (!type)
        return false;
    else if (isWeek) {
        if (type !== "string")
            return false;
        else {
            const res = READ_FROM_STR(time, format, handler, true);
            if (!res)
                return false;
            else {
                const [start, end] = res;
                return [DATE_TO_PARSE(start), DATE_TO_PARSE(end)];
            }
        }
    }
    else {
        let DATE;
        if (type === "string") {
            const { isError, date } = READ_FROM_STR(time, format, handler);
            if (isError)
                return false;
            else
                DATE = date;
        }
        else if (type === "timestamp") {
            DATE = new Date(time);
        }
        else if (type === "date") {
            DATE = time;
        }
        else
            return false;
        return DATE_TO_PARSE(DATE);
    }
}
exports.useDate = useDate;
